package com.probox.common.entity.utils;

import cn.hutool.core.io.resource.ClassPathResource;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;

/**
 * 获取平台证书 、 铭感信息加密、解密
 * @author Kite
 * @date 2021/6/29
 */
public class CertHelper {
    private KeyStore store;
    private final Object lock = new Object();
    private static KeyPair keyPair;


    private final static String v3 = "YouRuan20210603YouRuan2021060388";

    private static String url = "apiclient_cert.p12";

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String keyAlias = "Tenpay Certificate";

    /**
     * 对敏感信息加密
     * @param message 信息
     * @param certificate 私钥信息
     * @return
     * @throws IllegalBlockSizeException
     * @throws IOException
     */
    public static String rsaEncryptOAEP(String message, X509Certificate certificate)
            throws IllegalBlockSizeException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
            byte[] data = message.getBytes("utf-8");
            byte[] cipherdata = cipher.doFinal(data);
            return Base64.getEncoder().encodeToString(cipherdata);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("无效的证书", e);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
        }
    }


    /**
     * 敏感信息解密
     * @param waitDecrypt 待解密
     * @param privateKey
     * @return
     * @throws BadPaddingException
     * @throws IOException
     */
    public static String rsaDecryptOAEP(String waitDecrypt, PrivateKey privateKey)
            throws BadPaddingException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            byte[] data = Base64.getDecoder().decode(waitDecrypt);
            return new String(cipher.doFinal(data), "utf-8");
        } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("无效的私钥", e);
        } catch (BadPaddingException | IllegalBlockSizeException e) {
            throw new BadPaddingException("解密失败");
        }
    }


    /**
     * 获取公私钥.
     *
     * @param keyPass  password
     * @return the key pair
     */
    public KeyPair createPKCS12(String keyPass) throws FileNotFoundException {
        if (keyPair != null) {
            return keyPair;
        }
        ClassPathResource resource = new ClassPathResource(url);
        char[] pem = keyPass.toCharArray();
        try {
            synchronized (lock) {
                if (store == null) {
                    synchronized (lock) {
                        store = KeyStore.getInstance("PKCS12");
                        store.load(resource.getStream(), pem);
                    }
                }
            }
            X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
            certificate.checkValidity();

            // 证书的序列号 也有用
            String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
            // 证书的 公钥
            PublicKey publicKey = certificate.getPublicKey();
            // 证书的私钥
            PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);

            keyPair = new KeyPair(publicKey, storeKey);
            return keyPair;

        } catch (Exception e) {
            throw new IllegalStateException("Cannot load keys from store: " , e);
        }
    }


    /**
     * 获取平台证书
     * @return
     */
    public String getPlatformCertificate()  {
        //请求平台证书地址
        String certificatesUrl = "https://api.mch.weixin.qq.com/v3/certificates";
        WeChatRequest weChatRequest = new WeChatRequest();
        //获取平台证书信息（信息未解密）
        String body = weChatRequest.weChatGet(certificatesUrl);
        System.out.println(body);
        JSONObject jsonObject = JSONObject.parseObject(body);
        JSONArray data = jsonObject.getJSONArray("data");
        JSONObject o = (JSONObject) data.get(0);
        JSONObject encrypt_certificate = (JSONObject) o.get("encrypt_certificate");
        String nonce = encrypt_certificate.getString("nonce");
        String associated_data = encrypt_certificate.getString("associated_data");
        //密文
        String ciphertext = (String) encrypt_certificate.get("ciphertext");
        AesUtil aesUtil = null;
        try {
            aesUtil = new AesUtil(v3.getBytes("utf-8"));
            //解密证书
            return  aesUtil.decryptToString(associated_data.getBytes("utf-8"), nonce.getBytes("utf-8"), ciphertext);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }


    /**
     * 获取平台证书 X509Certificate
     * @param cert
     * @return
     */
    public X509Certificate fromString(String cert) {
        CertificateFactory certificateFactory = null;
        try {
            certificateFactory = CertificateFactory.getInstance
                    ("X.509");
            final String strCertificate = cert;

            final ByteArrayInputStream streamCertificate = new ByteArrayInputStream
                    (strCertificate.getBytes("UTF-8"));
            return (X509Certificate) certificateFactory.generateCertificate
                    (streamCertificate);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return null;
    }
}
